/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* 控制宏 */
#define LEFT 			0x27
#define RIGHT 			0x26
#define UP 				0X29
#define DOWM 			0x2A
#define ON				0xA7
#define OFF				0xA6

//oled显示尺寸
uint16_t const displayWidth                = 128;
uint16_t const displayHeight               = 64;

#define  SET_PIXEL     1
#define  RESET_PIXEL   0

/*  OLED显存
[0]0 1 2 3 ... 127	
[1]0 1 2 3 ... 127	
[2]0 1 2 3 ... 127	
[3]0 1 2 3 ... 127	
[4]0 1 2 3 ... 127	
[5]0 1 2 3 ... 127	
[6]0 1 2 3 ... 127	
[7]0 1 2 3 ... 127 */
static uint8_t OLED_RAM[8][128]; //定义GDDRAM缓存区

// 字符A的数据缓存
static uint8_t char_a[6] = {0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8 };

// 字符AA的数据缓存
//uint8_t char_aa[12] = { 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8, 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8, };

// 比如：Hello 是5个字符，每个字符6个字节；一共是30个字节；
uint8_t char_hello[6*5] = { 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8, 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8, };

void HAL_I2C_WriteByte(uint8_t addr, uint8_t data)
{
	uint8_t TxData[2] = { addr, data };
	HAL_I2C_Master_Transmit(&hi2c1, 0X78, (uint8_t*)TxData, 2, 10);
}

/**************************************************************
	 Prototype      : void WriteCmd(uint8_t IIC_Command)
	 Parameters     : IIC_Command
	 return					: none
	 Description    : 写命令
***************************************************************/
void WriteCmd(uint8_t IIC_Command)
{
	HAL_I2C_WriteByte(0x00, IIC_Command);
}

/**************************************************************
	 Prototype      : void WriteDat(uint8_t IIC_Data)
	 Parameters     : IIC_Data
	 return					: none
	 Description    : 写数据
***************************************************************/
void WriteDat(uint8_t IIC_Data)
{
	HAL_I2C_WriteByte(0x40, IIC_Data);
}

/**************************************************************
	 Prototype      : void OLED_RefreshRAM(void)
	 Parameters     : none
	 return					: none
	 Description    : 全屏填充
***************************************************************/

void OLED_RefreshRAM(void)
{
	// 页寻址模式填充
	for (uint16_t m = 0; m < displayHeight / 8; m++)
	{
		WriteCmd(0xb0 + m); //设置页地址b0~b7
		WriteCmd(0x00); //设置显示位置—列低地址00-0f
		WriteCmd(0x10); //设置显示位置—列高地址10-1f
		for (uint16_t n = 0; n < displayWidth; n++)
		{
			WriteDat(OLED_RAM[m][n]);
		}
	} 
}

/**************************************************************
	 Prototype      : void OLED_Fill(uint8_t fill_Data)
	 Parameters     : fill_Data 填充的1字节数据
	 return					: none
	 Description    : 全屏填充 0x00~0xff
***************************************************************/
void OLED_FullyFill(uint8_t fill_Data)
{
	for (uint16_t m = 0; m < displayHeight / 8; m++)
	{
		for (uint16_t n = 0; n < displayWidth; n++)
		{
			OLED_RAM[m][n] = fill_Data;
		}
	}
	
	OLED_RefreshRAM();
}

/**************************************************************
	 Prototype      : void OLED_FullyClear(void)
	 Parameters     : none
	 return					: none
	 Description    : 全屏清除
***************************************************************/
void OLED_FullyClear(void)
{
	OLED_FullyFill(RESET_PIXEL);
}

/**************************************************************
	 Prototype      : void OLED_RefreshRAM(void)
	 Parameters     : none
	 return					: none
	 Description    : 全屏填充
***************************************************************/


/**************************************************************
	 Prototype      : void OLED_Init(void)
	 Parameters     : none
	 return					: none
	 Description    : 初始化OLED模块
***************************************************************/
void OLED_Init(void) 
{
	HAL_Delay(500);
	
	WriteCmd(0xAE); //开显示
	WriteCmd(0x20); //设置内存寻址模式
	
	WriteCmd(0x10); //00，水平寻址模式;01，垂直寻址模式;10，页面寻址模式(重置);11，无效
	WriteCmd(0xb0); //为页面寻址模式设置页面开始地址，0-7
	WriteCmd(0x00); //---设置低列地址
	WriteCmd(0x10); //---设置高列地址

	WriteCmd(0xc8); //设置COM输出扫描方向
	WriteCmd(0x40); //--设置起始行地址
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度调节 0x00~0xff
	WriteCmd(0xa0); //--设置段重新映射0到127
	WriteCmd(0xa6); //--设置正常显示
	WriteCmd(0xa8); //--设置复用比(1 ~ 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,输出遵循RAM内容;0xa5,Output忽略RAM内容
	WriteCmd(0xd3); //-设置显示抵消
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--设置显示时钟分频/振荡器频率
	WriteCmd(0xf0); //--设置分率
	WriteCmd(0xd9); //--设置pre-charge时期
	WriteCmd(0x22); //
	WriteCmd(0xda); //--设置com大头针硬件配置
	WriteCmd(0x12);
	WriteCmd(0xdb); //--设置vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--设置DC-DC
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--打开oled面板
	
	OLED_FullyClear(); //清屏
}

/**************************************************************
	 Prototype      : void OLED_ON(void)
	 Parameters     : none
	 return					: none
	 Description    : 将OLED从休眠中唤醒
***************************************************************/
void OLED_ON(void)
{
	WriteCmd(0X8D); //设置电荷泵
	WriteCmd(0X14); //开启电荷泵
	WriteCmd(0XAF); //OLED唤醒
}

/**************************************************************
	 Prototype      : void OLED_OFF(void)
	 Parameters     : none
	 return					: none
	 Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
***************************************************************/
void OLED_OFF(void)
{
	WriteCmd(0X8D); //设置电荷泵
	WriteCmd(0X10); //关闭电荷泵
	WriteCmd(0XAE); //OLED休眠
}

/**************************************************************
	Prototype      :  void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel)
	Parameters     : 	x,y -- 起始点坐标(x:0~127, y:0~63);
										set_pixel	 该点的数据  SET_PIXEL = 1, RESET_PIXEL = 0
	return				 :  none
	Description    : 	设置坐标像素点数据
***************************************************************/
void OLED_SetPixel(int16_t x, int16_t y, uint8_t set_pixel)
{ 
	if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) {
		if (set_pixel) {
			OLED_RAM[y / 8][x] |= (0x01 << (y % 8));
		}  
		else {
			OLED_RAM[y / 8][x] &= ~(0x01 << (y % 8));
		}
	}
}

/**************************************************************
	Prototype      :  void OLED_GetPixel(int16_t x, int16_t y)
	Parameters     : 	x,y -- 起始点坐标(x:0~127, y:0~63);
	return				 :  PixelStatus 像素点状态 	SET_PIXEL = 1, RESET_PIXEL = 0
	Description    : 	获得坐标像素点数据
***************************************************************/


uint8_t OLED_GetPixel(int16_t x, int16_t y)
{
	if (OLED_RAM[y / 8][x] >> (y % 8) & 0x01)
		return SET_PIXEL;
	 
	return RESET_PIXEL;
}

void copy_char_a_to_ram() {
	
	// 0xC0 = 二进制的 11000000
	OLED_SetPixel(0, 0, RESET_PIXEL);
	OLED_SetPixel(0, 1, RESET_PIXEL);
	OLED_SetPixel(0, 2, RESET_PIXEL);
	OLED_SetPixel(0, 3, RESET_PIXEL);
	OLED_SetPixel(0, 4, RESET_PIXEL);
	OLED_SetPixel(0, 5, RESET_PIXEL);
	OLED_SetPixel(0, 6, SET_PIXEL);
	OLED_SetPixel(0, 7, SET_PIXEL);
}

// 最原始的getBits:
// 参数1： value   =  输入的值，比如 0xC0, 
// 参数2： bit_num =  想获取的位数，有效区间是 0 -- 7
uint8_t getBits(uint8_t value, uint8_t bit_num) {
	// 循环检查每一位，从最高位到最低位
	//for (int i = 7; i >= 0; i--) 
	{
		// 检查当前位是否为1
		if (value & (1 << bit_num)) {
			return 1; // printf("1");
		}
		else {
			return 0; //printf("0");
		}
	}
	//printf("\n"); // 打印换行
}

// v7: 增加屏幕的起始坐标： // 起始点: (start_x, start_y)
void copy_char_a_to_ram_v7(uint8_t start_x, uint8_t start_y, uint8_t *charArray, uint8_t arrayLen) {
	//, uint8_t arraySize     
    // 字符A的数据缓存: 先暂时挪进来

    // 例子数据：
    //uint8_t char_aa[12] = {0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8,     0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8,      };
	uint8_t i = 0, j = 0;

	for (j = 0; j < arrayLen; j++) {
		uint8_t value = charArray[j];
		for (i = 0; i < 8; i++) {
			OLED_SetPixel(start_x + j, start_y + i, getBits(value, i));
		}
	}
}


void copy_char_a_to_ram_v6(uint8_t *charArray, uint8_t arrayLen) {
	//, uint8_t arraySize     // 起始点(0,0)
    // 字符A的数据缓存: 先暂时挪进来

    // 例子数据：
    //uint8_t char_aa[12] = {0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8,     0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8,      };

    // v6: 传入字符AA, 字符的总长度应该是12, 这样连续输出12列，即可

    // v5: 字符A是传进来的, 不是固定写死的.
    // v4: 对字符A进行循环, 获取每一个缓存字节，一共6个
    // v3： 数据是： 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8
    // v2: 增加 getBits 的使用
    // v3: 增加循环
	uint8_t i = 0, j = 0;

	for (j = 0; j < arrayLen; j++) {
		uint8_t value = charArray[j];
		for (i = 0; i < 8; i++) {
			OLED_SetPixel(j, i, getBits(value, i));
		}
	}
}

void copy_char_a_to_ram_v5(uint8_t *charArray) {
	//, uint8_t arraySize     // 起始点(0,0)
    // 字符A的数据缓存: 先暂时挪进来
    //uint8_t char_a[6] = {0xC0, 0x38, 0x1E, 0x09, 0x0E,0xE8 };

    // v5: 字符A是传进来的, 不是固定写死的.
    // v4: 对字符A进行循环, 获取每一个缓存字节，一共6个
    // v3： 数据是： 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8
    // v2: 增加 getBits 的使用
    // v3: 增加循环
	uint8_t i = 0, j = 0;

	for (j = 0; j < 7; j++) {
		uint8_t value = charArray[j];
		for (i = 0; i < 8; i++) {
			OLED_SetPixel(j, i, getBits(value, i));
		}
	}
}

void copy_char_a_to_ram_v4() {
	// 起始点(0,0)
	
    // 字符A的数据缓存: 先暂时挪进来
	uint8_t char_a[6] = { 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8 };

	// v4: 对字符A进行循环, 获取每一个缓存字节，一共6个
	// v3： 数据是： 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8
	// v2: 增加 getBits 的使用
	// v3: 增加循环
	uint8_t i = 0, j = 0;

	for (j = 0; j < 7; j++) {
		uint8_t value = char_a[j];
		for (i = 0; i < 8; i++) {
			OLED_SetPixel(j, i, getBits(value, i));
		}
	}
}

void copy_char_a_to_ram_v3() {
	
	// 第3版算法： 数据是： 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8
	// v2: 增加 getBits 的使用
	// v3: 增加循环
	uint8_t i = 0;

	// 起始点(0,0)

	// 0xC0 = 二进制的 11000000，使用循环 
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(0, i, getBits(0xC0, i));
	}
	//OLED_SetPixel(0, 0, getBits(0xC0, 0));
	//OLED_SetPixel(0, 1, getBits(0xC0, 1));
	//OLED_SetPixel(0, 2, getBits(0xC0, 2));
	//OLED_SetPixel(0, 3, getBits(0xC0, 3));
	//OLED_SetPixel(0, 4, getBits(0xC0, 4));
	//OLED_SetPixel(0, 5, getBits(0xC0, 5));
	//OLED_SetPixel(0, 6, getBits(0xC0, 6));
	//OLED_SetPixel(0, 7, getBits(0xC0, 7));

	// 0x38 = 二进制的 0011 1000，使用循环 
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(1, i, getBits(0x38, i)); // 0
	}
	//OLED_SetPixel(1, 0, getBits(0x38, 0)); // 0
	//OLED_SetPixel(1, 1, getBits(0x38, 1)); // 0
	//OLED_SetPixel(1, 2, getBits(0x38, 2)); // 1
	//OLED_SetPixel(1, 3, getBits(0x38, 3)); // 1
	//OLED_SetPixel(1, 4, getBits(0x38, 4)); // 1
	//OLED_SetPixel(1, 5, getBits(0x38, 5)); // 0
	//OLED_SetPixel(1, 6, getBits(0x38, 6)); // 0
	//OLED_SetPixel(1, 7, getBits(0x38, 7)); // 0

	// 0x1E = 二进制的 0001 1110
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(2, i, getBits(0x1E, i)); // 0
	}
	// OLED_SetPixel(2, 0, getBits(0x1E, 0)); // 0
	// OLED_SetPixel(2, 1, getBits(0x1E, 1)); // 0
	// OLED_SetPixel(2, 2, getBits(0x1E, 2)); // 0
	// OLED_SetPixel(2, 3, getBits(0x1E, 3)); // 1
	// OLED_SetPixel(2, 4, getBits(0x1E, 4)); // 1
	// OLED_SetPixel(2, 5, getBits(0x1E, 5)); // 1
	// OLED_SetPixel(2, 6, getBits(0x1E, 6)); // 1
	// OLED_SetPixel(2, 7, getBits(0x1E, 7)); // 0

    // 0x09 = 二进制的 0000 1001
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(3, i, getBits(0x09, i)); // 0
	}

	// OLED_SetPixel(3, 0, getBits(0x09, 0)); // 0
	// OLED_SetPixel(3, 1, getBits(0x09, 1)); // 0
	// OLED_SetPixel(3, 2, getBits(0x09, 2)); // 0
	// OLED_SetPixel(3, 3, getBits(0x09, 3)); // 0
	// OLED_SetPixel(3, 4, getBits(0x09, 4)); // 1
	// OLED_SetPixel(3, 5, getBits(0x09, 5)); // 0
	// OLED_SetPixel(3, 6, getBits(0x09, 6)); // 0
	// OLED_SetPixel(3, 7, getBits(0x09, 7)); // 1

    // 0x0E = 二进制的 0000 1110
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(4, i, getBits(0x0E, i)); // 0
	}
	// OLED_SetPixel(4, 0, getBits(0x0E, 0)); // 0
	// OLED_SetPixel(4, 1, getBits(0x0E, 1)); // 0
	// OLED_SetPixel(4, 2, getBits(0x0E, 2)); // 0
	// OLED_SetPixel(4, 3, getBits(0x0E, 3)); // 0
	// OLED_SetPixel(4, 4, getBits(0x0E, 4));   // 1
	// OLED_SetPixel(4, 5, getBits(0x0E, 5));   // 1
	// OLED_SetPixel(4, 6, getBits(0x0E, 6));   // 1
	// OLED_SetPixel(4, 7, getBits(0x0E, 7)); // 0

    // 0xE8 = 二进制的 1110 1000
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(5, i, getBits(0xE8, i)); // 1    
	}
	// OLED_SetPixel(5, 0, getBits(0xE8, 0)); // 1
	// OLED_SetPixel(5, 1, getBits(0xE8, 1)); // 1
	// OLED_SetPixel(5, 2, getBits(0xE8, 2)); // 1
	// OLED_SetPixel(5, 3, getBits(0xE8, 3)); // 0
	// OLED_SetPixel(5, 4, getBits(0xE8, 4)); // 1
	// OLED_SetPixel(5, 5, getBits(0xE8, 5)); // 0
	// OLED_SetPixel(5, 6, getBits(0xE8, 6)); // 0
	// OLED_SetPixel(5, 7, getBits(0xE8, 7)); // 0
}

void copy_char_a_to_ram_v2() {
	
	// 第2版算法： 数据是： 0xC0, 0x38, 0x1E, 0x09, 0x0E, 0xE8
	// 增加 getBits 的使用

	// 起始点(0,0)

	// 0xC0 = 二进制的 11000000
	OLED_SetPixel(0, 0, getBits(0xC0, 0));
	OLED_SetPixel(0, 1, getBits(0xC0, 1));
	OLED_SetPixel(0, 2, getBits(0xC0, 2));
	OLED_SetPixel(0, 3, getBits(0xC0, 3));
	OLED_SetPixel(0, 4, getBits(0xC0, 4));
	OLED_SetPixel(0, 5, getBits(0xC0, 5));
	OLED_SetPixel(0, 6, getBits(0xC0, 6));
	OLED_SetPixel(0, 7, getBits(0xC0, 7));

	// 0x38 = 二进制的 0011 1000
	OLED_SetPixel(1, 0, getBits(0x38, 0)); // 0
	OLED_SetPixel(1, 1, getBits(0x38, 1)); // 0
	OLED_SetPixel(1, 2, getBits(0x38, 2)); // 1
	OLED_SetPixel(1, 3, getBits(0x38, 3)); // 1
	OLED_SetPixel(1, 4, getBits(0x38, 4)); // 1
	OLED_SetPixel(1, 5, getBits(0x38, 5)); // 0
	OLED_SetPixel(1, 6, getBits(0x38, 6)); // 0
	OLED_SetPixel(1, 7, getBits(0x38, 7)); // 0

	// 0x1E = 二进制的 0001 1110
	OLED_SetPixel(2, 0, getBits(0x1E, 0)); // 0
	OLED_SetPixel(2, 1, getBits(0x1E, 1)); // 0
	OLED_SetPixel(2, 2, getBits(0x1E, 2)); // 0
	OLED_SetPixel(2, 3, getBits(0x1E, 3)); // 1
	OLED_SetPixel(2, 4, getBits(0x1E, 4)); // 1
	OLED_SetPixel(2, 5, getBits(0x1E, 5)); // 1
	OLED_SetPixel(2, 6, getBits(0x1E, 6)); // 1
	OLED_SetPixel(2, 7, getBits(0x1E, 7)); // 0

    // 0x09 = 二进制的 0000 1001
	OLED_SetPixel(3, 0, getBits(0x09, 0)); // 0
	OLED_SetPixel(3, 1, getBits(0x09, 1)); // 0
	OLED_SetPixel(3, 2, getBits(0x09, 2)); // 0
	OLED_SetPixel(3, 3, getBits(0x09, 3)); // 0
	OLED_SetPixel(3, 4, getBits(0x09, 4)); // 1
	OLED_SetPixel(3, 5, getBits(0x09, 5)); // 0
	OLED_SetPixel(3, 6, getBits(0x09, 6)); // 0
	OLED_SetPixel(3, 7, getBits(0x09, 7)); // 1

    // 0x0E = 二进制的 0000 1110
	OLED_SetPixel(4, 0, getBits(0x0E, 0)); // 0
	OLED_SetPixel(4, 1, getBits(0x0E, 1)); // 0
	OLED_SetPixel(4, 2, getBits(0x0E, 2)); // 0
	OLED_SetPixel(4, 3, getBits(0x0E, 3)); // 0
	OLED_SetPixel(4, 4, getBits(0x0E, 4)); // 1
	OLED_SetPixel(4, 5, getBits(0x0E, 5)); // 1
	OLED_SetPixel(4, 6, getBits(0x0E, 6)); // 1
	OLED_SetPixel(4, 7, getBits(0x0E, 7)); // 0

    // 0xE8 = 二进制的 1110 1000
	OLED_SetPixel(5, 0, getBits(0xE8, 0)); // 1
	OLED_SetPixel(5, 1, getBits(0xE8, 1)); // 1
	OLED_SetPixel(5, 2, getBits(0xE8, 2)); // 1
	OLED_SetPixel(5, 3, getBits(0xE8, 3)); // 0
	OLED_SetPixel(5, 4, getBits(0xE8, 4)); // 1
	OLED_SetPixel(5, 5, getBits(0xE8, 5)); // 0
	OLED_SetPixel(5, 6, getBits(0xE8, 6)); // 0
	OLED_SetPixel(5, 7, getBits(0xE8, 7)); // 0
}

// 从 (0,0) --->  (64,0) 画一根横线
//	y = 0;
//	for (x = 0; x < 64; x++)
//	{
//		OLED_SetPixel(x, y, SET_PIXEL);
//	}
//	
//	// 从 (0,0) --->  (0,30) 画一根竖线
//	x = 0;
//	for (y = 0; y < 30; y++) {
//		OLED_SetPixel(x, y, SET_PIXEL);
//	}
//	
//	// 从 (0,30) --->  (64,30) 画一根横线
//	y = 30;
//	for (x = 0; x < 64; x++)
//	{
//		OLED_SetPixel(x, y, SET_PIXEL);
//	}
//	
//	// 从 (64,0) --->  (64,30) 画一根竖线
//	x = 64;
//	for (y = 0; y < 30; y++) {
//		OLED_SetPixel(x, y, SET_PIXEL);
//	}

void copy_char_B_to_ram_v3() {
	
	uint16_t b[] =  {
		 0x08,
		0xF8,
		0x88,
		0x88,
		0x88,
		0x70,
		0x00,
		0x00,
		0x20,
		0x3F,
		0x20,
		0x20,
		0x20,
		0x11,
		0x0E,
		0x00
	};
	uint8_t i=0, j=0;
	
	// first row
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(0, i, getBits(0x08, i));
	}//#1
	for (i = 0; i < 8; i++) {
	    OLED_SetPixel(1, i, getBits(0xF8, i));
    }//#2
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(2, i, getBits(0x88, i));
	}//#3
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(3, i, getBits(0x88, i));
	}//#4
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(4, i, getBits(0x88, i));
	}//#5
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(5,i,getBits(0x70,i));
	}//#6
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(6,i,getBits(0x00,i));
	}//#7
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(7, i, getBits(0x00, i));
	}//#8
	
	// second row
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(0, i+8, getBits(0x20, i));
	}//#9
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(1, i + 8, getBits(0x3F, i));
	}//#10
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(2, i + 8, getBits(0x20, i));
	}//#11
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(3, i + 8, getBits(0x20, i));
	}//#12
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(4, i + 8, getBits(0x20, i));
	}//#13
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(5, i + 8, getBits(0x11, i));
	}//#14
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(6, i + 8, getBits(0x0E, i));
	}//#15
	for (i = 0; i < 8; i++) {
		OLED_SetPixel(7, i + 8, getBits(0x00, i));
	}//#16
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t i = 0, x = 0, y = 0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
	

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */

	OLED_Init();
	
	// copy_char_a_to_ram_v6(char_aa, sizeof(char_aa));
	// start_x = 32, start_y = 10
	//copy_char_a_to_ram_v7(32, 10, char_aa, sizeof(char_aa));
	
//	copy_char_a_to_ram_v7(5, 10, char_hello, sizeof(char_hello));
////	
//	OLED_RefreshRAM();
	
//	uint8_t char_b[16]= 
//	{ 
//		0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
//		0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00 
//	};
//	int p = 0;
//	for (int row = 0; row < 8; row++) {
//
//		uint8_t value = char_b[row+p*8];
//		for (int l = 0; l < 8; l++) {
//			if (value & (1 << l)) {
//				OLED_SetPixel(row, l+p*8, 1);}
//				else {
//				OLED_SetPixel(row, l+p*8, 0);}
//		}
//		if (row == 7)
//		{
//			p = 1;
//			row = 0;
//		}
//			
//	}
	copy_char_B_to_ram_v3();
//	copy_char_a_to_ram_v3();
  /* USER CODE END 2 */
	OLED_RefreshRAM();
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
